package main

import (
	"fmt"
	"time"

	modbus "gitee.com/barryzxy/gomodbus"
)

// 自动重连客户端示例
// 展示如何使用增强的自动重连功能，提供更好的连接稳定性

func main() {
	fmt.Println("=== Modbus 自动重连客户端示例 ===")
	fmt.Println("此示例展示增强的自动重连功能，提供更强的连接稳定性")

	// 1. 创建支持自动重连的客户端
	fmt.Println("\n🔧 创建增强功能客户端...")

	provider := modbus.NewTCPClientProvider("localhost:502", modbus.WithEnableLogger())
	client := modbus.NewClient(provider,
		// 启用自动重连功能
		modbus.WithAutoRetry(true),
		modbus.WithMaxRetries(5),               // 最大重试5次
		modbus.WithRetryDelay(2*time.Second),   // 重试间隔2秒
		modbus.WithEnhancedErrorHandling(true), // 启用增强错误处理
	)

	fmt.Println("✅ 客户端创建成功")
	fmt.Println("📋 增强功能配置：")
	fmt.Println("  🔄 自动重连: 启用")
	fmt.Println("  🔢 最大重试次数: 5")
	fmt.Println("  ⏱️  重试间隔: 2秒")
	fmt.Println("  📊 增强错误处理: 启用")

	// 2. 尝试连接（可能失败，但会自动重试）
	fmt.Println("\n🔌 尝试连接到服务器...")
	fmt.Println("💡 注意：如果连接失败，将自动进行重试")

	startTime := time.Now()
	err := client.Connect()
	connectDuration := time.Since(startTime)

	if err != nil {
		// 即使有自动重试，最终仍可能失败
		fmt.Printf("❌ 连接最终失败: %v\n", err)
		fmt.Printf("⏱️  总尝试时间: %v\n", connectDuration)
		fmt.Println("\n🔧 故障排查建议：")
		fmt.Println("  1. 检查Modbus服务器是否运行")
		fmt.Println("  2. 确认端口502是否可用")
		fmt.Println("  3. 检查防火墙设置")
		fmt.Println("  4. 验证网络连接")

		// 演示连接重试逻辑
		demonstrateRetryLogic()
		return
	}

	fmt.Printf("✅ 连接成功！耗时: %v\n", connectDuration)
	defer client.Close()

	// 3. 正常操作测试
	fmt.Println("\n📊 执行正常操作测试...")
	testNormalOperations(client)

	// 4. 连接稳定性测试
	fmt.Println("\n🔄 连接稳定性测试...")
	testConnectionStability(client)

	// 5. 网络中断模拟
	fmt.Println("\n🌐 网络中断恢复测试...")
	testNetworkInterruption(client)

	// 6. 长时间运行测试
	fmt.Println("\n⏰ 长时间运行稳定性测试...")
	testLongRunningStability(client)

	fmt.Println("\n🎯 自动重连功能总结：")
	fmt.Println("✅ 自动检测连接问题")
	fmt.Println("✅ 智能重试机制")
	fmt.Println("✅ 指数退避策略")
	fmt.Println("✅ 详细的错误上下文")
	fmt.Println("✅ 透明的错误恢复")
}

// demonstrateRetryLogic 演示重试逻辑
func demonstrateRetryLogic() {
	fmt.Println("\n🎬 演示自动重试逻辑...")

	// 模拟重试过程
	for attempt := 1; attempt <= 5; attempt++ {
		fmt.Printf("🔄 尝试连接 #%d...\n", attempt)

		// 模拟连接尝试
		time.Sleep(500 * time.Millisecond)

		if attempt < 5 {
			fmt.Printf("❌ 连接失败，%d秒后重试...\n", attempt*2)
			time.Sleep(time.Duration(attempt) * time.Second)
		} else {
			fmt.Println("❌ 达到最大重试次数，连接失败")
		}
	}

	fmt.Println("\n💡 实际使用中的重试特性：")
	fmt.Println("  🧠 智能错误分类 - 只重试可恢复的错误")
	fmt.Println("  ⏱️  指数退避 - 避免过度重试")
	fmt.Println("  📊 重试统计 - 记录重试次数和成功率")
	fmt.Println("  🎯 上下文保持 - 保持原始请求信息")
}

// testNormalOperations 测试正常操作
func testNormalOperations(client modbus.Client) {
	operations := []struct {
		name string
		fn   func() error
	}{
		{
			"读取线圈",
			func() error {
				_, err := client.ReadCoils(1, 0, 10)
				return err
			},
		},
		{
			"读取保持寄存器",
			func() error {
				_, err := client.ReadHoldingRegisters(1, 0, 5)
				return err
			},
		},
		{
			"写入单个线圈",
			func() error {
				return client.WriteSingleCoil(1, 0, true)
			},
		},
		{
			"写入单个寄存器",
			func() error {
				return client.WriteSingleRegister(1, 0, 12345)
			},
		},
	}

	successCount := 0
	for _, op := range operations {
		fmt.Printf("  执行 %s: ", op.name)
		err := op.fn()
		if err != nil {
			fmt.Printf("失败 - %v\n", err)
		} else {
			fmt.Println("成功")
			successCount++
		}
	}

	fmt.Printf("✅ 正常操作完成，成功率: %d/%d (%.1f%%)\n",
		successCount, len(operations),
		float64(successCount)/float64(len(operations))*100)
}

// testConnectionStability 测试连接稳定性
func testConnectionStability(client modbus.Client) {
	const testDuration = 30 * time.Second
	const operationInterval = 1 * time.Second

	fmt.Printf("执行 %v 的连接稳定性测试...\n", testDuration)

	startTime := time.Now()
	operationCount := 0
	successCount := 0
	errorCount := 0

	ticker := time.NewTicker(operationInterval)
	defer ticker.Stop()

	timeout := time.After(testDuration)

	for {
		select {
		case <-timeout:
			duration := time.Since(startTime)
			fmt.Printf("✅ 稳定性测试完成\n")
			fmt.Printf("  📊 总操作数: %d\n", operationCount)
			fmt.Printf("  ✅ 成功操作: %d\n", successCount)
			fmt.Printf("  ❌ 失败操作: %d\n", errorCount)
			fmt.Printf("  📈 成功率: %.2f%%\n", float64(successCount)/float64(operationCount)*100)
			fmt.Printf("  ⏱️  平均操作间隔: %v\n", duration/time.Duration(operationCount))
			return

		case <-ticker.C:
			operationCount++

			// 执行简单的读取操作
			_, err := client.ReadHoldingRegisters(1, 0, 1)
			if err != nil {
				errorCount++
				fmt.Printf("  ⚠️  操作 #%d 失败: %v\n", operationCount, err)
			} else {
				successCount++
				if operationCount%5 == 0 {
					fmt.Printf("  ✅ 操作 #%d 成功\n", operationCount)
				}
			}
		}
	}
}

// testNetworkInterruption 测试网络中断恢复
func testNetworkInterruption(client modbus.Client) {
	fmt.Println("模拟网络中断场景...")
	fmt.Println("💡 在实际环境中，自动重连会处理以下情况：")
	fmt.Println("  🌐 网络连接中断")
	fmt.Println("  🖥️  服务器重启")
	fmt.Println("  🔌 连接超时")
	fmt.Println("  🔄 临时网络故障")

	// 模拟一系列可能失败的操作
	scenarios := []struct {
		name        string
		description string
		simulate    func() error
	}{
		{
			"网络延迟",
			"模拟高延迟网络环境",
			func() error {
				time.Sleep(100 * time.Millisecond) // 模拟延迟
				_, err := client.ReadCoils(1, 0, 5)
				return err
			},
		},
		{
			"间歇性连接",
			"模拟不稳定的网络连接",
			func() error {
				// 快速连续操作测试连接稳定性
				for i := 0; i < 3; i++ {
					_, err := client.ReadHoldingRegisters(1, uint16(i), 1)
					if err != nil {
						return err
					}
					time.Sleep(50 * time.Millisecond)
				}
				return nil
			},
		},
		{
			"大数据传输",
			"模拟大量数据传输场景",
			func() error {
				// 读取较大的数据块
				_, err := client.ReadHoldingRegisters(1, 0, 50)
				return err
			},
		},
	}

	for _, scenario := range scenarios {
		fmt.Printf("  🧪 测试场景: %s\n", scenario.name)
		fmt.Printf("     描述: %s\n", scenario.description)

		start := time.Now()
		err := scenario.simulate()
		duration := time.Since(start)

		if err != nil {
			fmt.Printf("     ❌ 失败: %v (耗时: %v)\n", err, duration)
			fmt.Println("     🔄 自动重连机制将处理此类错误")
		} else {
			fmt.Printf("     ✅ 成功 (耗时: %v)\n", duration)
		}

		time.Sleep(500 * time.Millisecond) // 间隔
	}
}

// testLongRunningStability 测试长时间运行稳定性
func testLongRunningStability(client modbus.Client) {
	const testDuration = 60 * time.Second
	const operationInterval = 2 * time.Second

	fmt.Printf("执行 %v 的长时间稳定性测试...\n", testDuration)
	fmt.Println("💡 此测试验证自动重连在长时间运行中的表现")

	startTime := time.Now()
	operationCount := 0
	errorCount := 0
	reconnectCount := 0

	ticker := time.NewTicker(operationInterval)
	defer ticker.Stop()

	timeout := time.After(testDuration)

	// 操作序列
	operations := []func() error{
		func() error { _, err := client.ReadCoils(1, 0, 8); return err },
		func() error { _, err := client.ReadHoldingRegisters(1, 0, 4); return err },
		func() error { return client.WriteSingleCoil(1, 0, operationCount%2 == 0) },
		func() error { return client.WriteSingleRegister(1, 0, uint16(operationCount)) },
	}

	for {
		select {
		case <-timeout:
			duration := time.Since(startTime)
			fmt.Printf("✅ 长时间稳定性测试完成\n")
			fmt.Printf("  📊 总操作数: %d\n", operationCount)
			fmt.Printf("  ❌ 错误次数: %d\n", errorCount)
			fmt.Printf("  🔄 重连次数: %d (估计)\n", reconnectCount)
			fmt.Printf("  📈 可用性: %.2f%%\n", float64(operationCount-errorCount)/float64(operationCount)*100)
			fmt.Printf("  ⏱️  运行时间: %v\n", duration)
			fmt.Printf("  🚀 操作频率: %.1f ops/min\n", float64(operationCount)/duration.Minutes())
			return

		case <-ticker.C:
			operationCount++
			op := operations[operationCount%len(operations)]

			err := op()
			if err != nil {
				errorCount++
				// 检查是否是连接相关错误
				errorStr := err.Error()
				if contains(errorStr, "connection") || contains(errorStr, "timeout") {
					reconnectCount++
					fmt.Printf("  🔄 检测到连接问题 #%d: %v\n", operationCount, err)
					fmt.Println("     自动重连机制正在处理...")
				} else {
					fmt.Printf("  ❌ 操作错误 #%d: %v\n", operationCount, err)
				}
			} else {
				if operationCount%10 == 0 {
					fmt.Printf("  ✅ 操作 #%d 完成，连接稳定\n", operationCount)
				}
			}
		}
	}
}

// contains 检查字符串是否包含子串
func contains(s, substr string) bool {
	return len(s) >= len(substr) &&
		(s == substr ||
			len(s) > len(substr) &&
				(s[:len(substr)] == substr ||
					s[len(s)-len(substr):] == substr ||
					indexOfSubstring(s, substr) >= 0))
}

// indexOfSubstring 简单的子串搜索
func indexOfSubstring(s, substr string) int {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return i
		}
	}
	return -1
}
